package com.main;

import java.util.List;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.hibernate.Criteria;

public class ManageEmployee {
	private static SessionFactory factory;
	private static ServiceRegistry serviceRegistry;

	public static void main(String[] args) {
		try {
			Configuration configuration = new Configuration();
			configuration.setInterceptor(new MyInterceptor());
			configuration.configure();
			serviceRegistry = new ServiceRegistryBuilder().applySettings(
					configuration.getProperties()).buildServiceRegistry();

			factory = configuration
					.addPackage("com.main")
					// add package if used.
					.addAnnotatedClass(Employee.class)
					.addAnnotatedClass(Address.class)
					.buildSessionFactory(serviceRegistry);

		} catch (Throwable ex) {
			System.err.println("Failed to create sessionFactory object." + ex);
			throw new ExceptionInInitializerError(ex);
		}
		ManageEmployee ME = new ManageEmployee();

		// * Let us have one address object
		// Address address1 =
		// ME.addAddress("23 Avenue","Washington","DC","222");

		// Add employee records in the database
		// Integer empID1 = ME.addEmployee("Barak", "Obama", 7000, address1);
		/* Add few employee records in database */
		// Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
		// Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
		// Integer empID3 = ME.addEmployee("John", "Paul", 10000);

		/* List down all the employees */
		// ME.listEmployees();

		/* Update employee's records */
		// ME.updateEmployee(empID1, 5000);

		/* Delete an employee from the database */
		// ME.deleteEmployee(empID2);

		/* List down new list of the employees */
		ME.listEmployees();

		ME.countEmployee();
		ME.totalSalary();
		
		ME.listCriteriaEmpl();
	}

	/* Method to add an address record in the database */
	public Address addAddress(String street, String city, String state,
			String zipcode) {
		Session session = factory.openSession();
		Transaction tx = null;
		Integer addressID = null;
		Address address = null;
		try {
			tx = session.beginTransaction();
			address = new Address(street, city, state, zipcode);
			addressID = (Integer) session.save(address);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return address;
	}

	/* Method to add an employee record in the database */
	public Integer addEmployee(String fname, String lname, int salary,
			Address address) {
		Session session = factory.openSession();
		Transaction tx = null;
		Integer employeeID = null;
		try {
			tx = session.beginTransaction();
			Employee employee = new Employee(fname, lname, salary, address);
			employeeID = (Integer) session.save(employee);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
		return employeeID;
	}

	/* Method to list all the employees detail */
	public void listEmployees() {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			List employees = session.createQuery("FROM Employee").list();
			for (Iterator iterator1 = employees.iterator(); iterator1.hasNext();) {
				Employee employee = (Employee) iterator1.next();
				System.out.print("First Name: " + employee.getFirstName());
				System.out.print("  Last Name: " + employee.getLastName());
				System.out.println("  Salary: " + employee.getSalary());

				Address add = employee.getAddress();
				if (add != null) {
					System.out.println("Address ");

					System.out.println("\tStreet: " + add.getStreet());
					System.out.println("\tCity: " + add.getCity());
					System.out.println("\tState: " + add.getState());
					System.out.println("\tZipcode: " + add.getZipcode());
				}
				;
			}
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	public void listCriteriaEmpl() {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Criteria cr = session.createCriteria(Employee.class);
			// To get records having salary more than 2000
			cr.add(Restrictions.gt("salary", 5000));

			// To sort records in descening order
			cr.addOrder(Order.desc("salary"));

			// To sort records in ascending order
			//cr.addOrder(Order.asc("salary"));

			List results = cr.list();
			for(Iterator it1 = results.iterator();it1.hasNext();){
				Employee empl = (Employee)it1.next();
				System.out.print("First Name: " + empl.getFirstName());
				System.out.print("  Last Name: " + empl.getLastName());
				System.out.println("  Salary: " + empl.getSalary());
			};
			
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	/* Method to update address for an employee */
	public void updateEmployee(Integer EmployeeID, Address address) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Employee employee = (Employee) session.get(Employee.class,
					EmployeeID);

			if (address != null) {
				employee.setAddress(address);
			}
			;

			session.update(employee);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	/* Method to UPDATE salary for an employee */
	public void updateEmployee(Integer EmployeeID, int salary) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Employee employee = (Employee) session.get(Employee.class,
					EmployeeID);
			employee.setSalary(salary);
			session.update(employee);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	/* Method to DELETE an employee from the records */
	public void deleteEmployee(Integer EmployeeID) {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Employee employee = (Employee) session.get(Employee.class,
					EmployeeID);
			session.delete(employee);
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	/* Method to print total number of records */
	public void countEmployee() {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Criteria cr = session.createCriteria(Employee.class);

			// To get total row count.
			cr.setProjection(Projections.rowCount());
			List rowCount = cr.list();

			System.out.println("Total Count: " + rowCount.get(0));
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}

	/* Method to print sum of salaries */
	public void totalSalary() {
		Session session = factory.openSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			Criteria cr = session.createCriteria(Employee.class);

			// To get total salary.
			cr.setProjection(Projections.sum("salary"));
			List totalSalary = cr.list();

			System.out.println("Total Salary: " + totalSalary.get(0));
			tx.commit();
		} catch (HibernateException e) {
			if (tx != null)
				tx.rollback();
			e.printStackTrace();
		} finally {
			session.close();
		}
	}
}